package com.ayf.payment.game.api.task.reissue;

import com.ayf.payment.game.api.dto.PartitionChangeDTO;
import com.ayf.payment.game.api.dto.criteria.ReissueAllCriteria;
import com.ayf.payment.game.api.entity.ReissueAllTask;
import com.ayf.payment.game.api.service.PartitionService;
import com.ayf.payment.game.api.service.ReissueAllTaskService;
import com.ayf.payment.game.api.service.ReissueRecordService;
import com.ayf.payment.game.api.utils.DateTimeUtil;
import com.ayf.payment.game.api.utils.JsonUtils;
import com.ayf.payment.game.api.utils.SnowFlakeUtils;
import com.swwx.charm.commons.lang.utils.LogPortal;
import com.swwx.charm.zookeeper.exception.GetLockFailedException;
import com.swwx.charm.zookeeper.exception.ReleaseLockFailedException;
import com.swwx.charm.zookeeper.lock.DistributedLock;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @author wwl
 * @description:
 * @date 2020/10/28 21:25
 */
@Component
public abstract class ReissueRecordResultTask {
    @Autowired
    private ReissueRecordService reissueRecordService;

    @Autowired
    PartitionService partitionService;

    @Autowired
    private ReissueAllTaskService reissueAllTaskService;

    protected void run(DistributedLock distributedLock) {
        boolean lock = false;
        String traceId = SnowFlakeUtils.getTraceId();
        String lockName = this.getClass().getSimpleName().concat(System.getenv("XY_GAME_PAY_LOCK_FLAG"));
        try {
            if (lock = distributedLock.getLock(lockName)) {
                String autoeissueTime = DateTimeUtil.getTimeMinutes(new Date());
                ReissueAllCriteria reissue = new ReissueAllCriteria();
                reissue.setAutoTeissueTime(autoeissueTime);
                List<ReissueAllTask> list = reissueAllTaskService.selectByTiming(reissue);
                int size=0;
                if(null!=list){
                    size=list.size();
                }
                LogPortal.info("(ReissueRecordAllTask-Time-strat)开始执行定时整区补任务 时间：[{}],执行条数[{}],执行数据[{}]",autoeissueTime,size, JsonUtils.strToJson(list));
                if(size>0) {
                    final CountDownLatch countDownLatch = new CountDownLatch(list.size());
                    for (ReissueAllTask rat : list) {
                        submit(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    PartitionChangeDTO partition = partitionService.selectPartitionChangeDTO(rat.getMerchantId(), rat.getPartitionId());
                                    if(partition ==null || StringUtils.isEmpty(partition.getId())){
                                        LogPortal.info("(ReissueRecordAllTask-PartitionId[{}])执行定时整区补任务,分区不存在或已删除 商户ID[{}]", rat.getPartitionId(), rat.getMerchantId());
                                        rat.setReissueStatus(-1);
                                        reissueAllTaskService.update(rat);
                                    }else {
                                        LogPortal.info("(ReissueRecordAllTask-PartitionId[{}])执行定时整区补任务,商户ID[{}]", rat.getPartitionId(), rat.getMerchantId());
                                        reissueRecordService.reissueAll(rat,0);
                                    }
                                } catch (Exception e) {
                                    LogPortal.error("{} (ReissueRecordAllTask-PartitionId[{}])执行定时整区补任务,分区名[{}]异常，错误描述:{}",e, traceId,rat.getPartitionId(), rat.getPartitionName(),e.getMessage());
                                }finally {
                                    //线程执行完成之后标记信号表示完成
                                    countDownLatch.countDown();
                                }
                            }
                        });
                    }
                    //等待线程池任务执行完毕
                    countDownLatch.await();
                }
            }
        } catch (GetLockFailedException e) {
            LogPortal.error("{} >>> [DISTRIBUTED_LOCK_ACQUIRE_FAILED_ZK] 分布式锁获取失败,锁名称为:{}", traceId, lockName);
            LogPortal.error("{} >>> {} 获取lock失败", e, traceId, lockName);
        } catch (Exception e) {
            LogPortal.error("{} >>> {} 任务执行出错 ", e, traceId, lockName);
        } finally {
            if (lock) {
                LogPortal.info(traceId + " >>> " + lockName + " finished.");
                try {
                    distributedLock.releaseLock(lockName);
                } catch (ReleaseLockFailedException e) {
                    LogPortal.error("{} >>> [DISTRIBUTED_LOCK_RELEASE_FAILED_ZK] 分布式锁释放失败,锁名称为:{}", traceId, lockName);
                    LogPortal.error("{} >>> {} 释放失败", e, traceId, lockName);
                }
            }
        }
    }

    public abstract void submit(Runnable task);
}
